﻿namespace NJQuery {
	using System;
	using System.ComponentModel;

	/// <summary>
	/// Defines a predefined or custom <see cref="Accordion"/> widget animation.
	/// </summary>
	[TypeConverter(typeof(AccordionAnimationConverter))]
	public struct AccordionAnimation : IComplexProperty, IEquatable<AccordionAnimation> {


		#region Static Readonly Fields: Standard values

		/// <summary>
		/// No animation will be used by the Accordion widget (initialized control with a value of "false").
		/// </summary>
		public static readonly AccordionAnimation False = new AccordionAnimation();

		/// <summary>
		/// The basic linear "slide" animation will be used by the Accordion widget when panels are activated.
		/// </summary>
		public static readonly AccordionAnimation Slide = new AccordionAnimation(AccordionStandardAnimation.Slide);

		/// <summary>
		/// The Accordion widget will use the standard "easeslide" animation when panels are activated.
		/// </summary>
		public static readonly AccordionAnimation EaseSlide = new AccordionAnimation(AccordionStandardAnimation.EaseSlide);

		/// <summary>
		/// The Accordion widget will use the standard "bounceslide" animation when panels are activated.
		/// </summary>
		public static readonly AccordionAnimation BounceSlide = new AccordionAnimation(AccordionStandardAnimation.BounceSlide);

		#endregion


		#region Static Methods

		/// <summary>
		/// Converts a string representation to its <see cref="AccordionAnimation"/> equivalent.
		/// </summary>
		/// <param name="text">A string containing the value to convert.</param>
		/// <returns>The parsed value.</returns>
		public static AccordionAnimation Parse(string text) {

			if(string.IsNullOrEmpty(text)) return False;

			//TODO: Write a Enum.TryParse!!!
			try {
				return new AccordionAnimation((AccordionStandardAnimation)Enum.Parse(typeof(AccordionStandardAnimation), text));
			} catch(ArgumentException) { }

			return new AccordionAnimation(text);
		}

		#endregion


		#region Fields

		private AccordionStandardAnimation standardAnimation;
		private string controlId;

		#endregion


		#region Constructors

		/// <summary>
		/// Initializes a new <see cref="AccordionAnimation"/> value using a standard Accordion widget animation definition.
		/// </summary>
		/// <param name="standardAnimation">The standard Accordion widget animation to use.</param>
		/// <exception cref="ArgumentException">Standard animation not defined.</exception>
		public AccordionAnimation(AccordionStandardAnimation standardAnimation) {
			if(!Enum.IsDefined(typeof(AccordionStandardAnimation), standardAnimation)) throw new ArgumentException("Value not defined.", "standardAnimation");

			this.standardAnimation = standardAnimation;
			controlId = null;
		}

		/// <summary>
		/// Initializes a new <see cref="AccordionAnimation"/> value using a custom Accordion widget animation definition.
		/// </summary>
		/// <param name="controlId">The control ID of the animation definition to use.</param>
		/// <exception cref="ArgumentNullException">Value cannot be null.</exception>
		/// <exception cref="ArgumentException">A value is required.</exception>
		public AccordionAnimation(string controlId) {
			if(controlId == null) throw new ArgumentNullException("controlId");
			if(controlId.Length == 0) throw new ArgumentException("A value is required.", "controlId");

			standardAnimation = AccordionStandardAnimation.False;
			this.controlId = controlId;
		}

		#endregion


		#region Properties

		/// <summary>
		/// Gets the the standard animation to use, if applicable.
		/// </summary>
		public AccordionStandardAnimation? StandardAnimation {
			get { return controlId == null ? standardAnimation : (AccordionStandardAnimation?)null; }
		}

		/// <summary>
		/// Gets the ID of a server effect definition to use, if applicable.
		/// </summary>
		public string ControlId {
			get { return controlId; }
		}

		/// <summary>
		/// Gets whether or not the accordion is animated.
		/// </summary>
		public bool IsAnimated {
			get { return standardAnimation != AccordionStandardAnimation.False || controlId != null; }
		}

		#endregion


		#region Methods: Object management

		/// <summary>
		/// Determines whether or not the specified object is equal to the current <see cref="AccordionAnimation"/> value.
		/// </summary>
		/// <param name="obj">The <see cref="Object"/> to compare.</param>
		/// <returns>Whether or not the provided object is equal.</returns>
		public override bool Equals(object obj) {
			if(obj is AccordionAnimation) return this == (AccordionAnimation)obj;
			return false;
		}

		/// <summary>
		/// Determines whether or not the specified <see cref="AccordionAnimation"/> is equal to the current <see cref="AccordionAnimation"/> value.
		/// </summary>
		/// <param name="other">The <see cref="AccordionAnimation"/> to compare.</param>
		/// <returns>Whether or not the provided <see cref="AccordionAnimation"/> value is equal.</returns>
		public bool Equals(AccordionAnimation other) {
			return this == other;
		}

		/// <summary>
		/// Serves as a hash function for <see cref="AccordionAnimation"/>.
		/// </summary>
		/// <returns>The hash value associated with the contained data.</returns>
		public override int GetHashCode() {
			//TODO: Have TheMuuj check it.
			return controlId == null ? standardAnimation.GetHashCode() : controlId.GetHashCode();
		}

		/// <summary>
		/// Returns a <see cref="String"/> that represents the current <see cref="AccordionAnimation"/> value.
		/// </summary>
		/// <returns>The string representation.</returns>
		public override string ToString() {
			return controlId ?? standardAnimation.ToString();
		}

		/// <summary>
		/// Returns a literal JavaScript value used to represent the server value on the client.
		/// </summary>
		/// <returns>The client script value.</returns>
		public string ToClientSource() {
			if(controlId == null) return standardAnimation.ToClientSource();
			return ScriptBuilder.NullLiteral;
		}

		#endregion


		#region Operators

		/// <summary>
		/// Compares the equality of two <see cref="AccordionAnimation"/> values.
		/// </summary>
		/// <param name="value0">The first value.</param>
		/// <param name="value1">The second value.</param>
		/// <returns>Whether or not the two <see cref="AccordionAnimation"/> values are equal.</returns>
		public static bool operator ==(AccordionAnimation value0, AccordionAnimation value1) {
			return value0.standardAnimation == value1.standardAnimation && value0.controlId == value1.controlId;
		}

		/// <summary>
		/// Compares the inequality of two <see cref="AccordionAnimation"/> values.
		/// </summary>
		/// <param name="value0">The first value.</param>
		/// <param name="value1">The second value.</param>
		/// <returns>Whether or not the two <see cref="AccordionAnimation"/> values are distinct.</returns>
		public static bool operator !=(AccordionAnimation value0, AccordionAnimation value1) {
			return value0.standardAnimation != value1.standardAnimation || value0.controlId != value1.controlId;
		}

		#endregion


	}

}